/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-02-01     xuxl       the first version
 */
#include "fram.h"
#include "rtthread.h"
#include "spi.h"
#include "ic.h"
#include "periodic.h"


/**
  * @brief  拉低FRAM芯片的CS引脚
  * @param  None
  * @retval None
  */
static void FRAM_CsLow(void)
{
    HAL_GPIO_WritePin(FRAM_CS_GPIO_Port, FRAM_CS_Pin, GPIO_PIN_RESET);
}

/**
  * @brief  拉高FRAM芯片的CS引脚
  * @param  None
  * @retval None
  */
static void FRAM_CsHigh(void)
{
    HAL_GPIO_WritePin(FRAM_CS_GPIO_Port, FRAM_CS_Pin, GPIO_PIN_SET);
}

/**
  * @brief  使能芯片WP引脚，以允许对状态寄存器的写操作
  * @param  None
  * @retval None
  */
static void FRAM_WriteStatusRegisterEnable(void)
{
    HAL_GPIO_WritePin(FRAM_WP_GPIO_Port, FRAM_WP_Pin, GPIO_PIN_SET);
}

/**
  * @brief  禁止芯片WP引脚，以禁止对状态寄存器的写操作
  * @param  None
  * @retval None
  */
void FRAM_WriteStatusRegisterDisable(void)
{
    HAL_GPIO_WritePin(FRAM_WP_GPIO_Port, FRAM_WP_Pin, GPIO_PIN_RESET);
}


/**
  * @brief  FRAM延时
  * @param  None
  * @retval None
  */
void FRAM_Delay(uint8_t ms)
{
    rt_thread_mdelay(ms);
}

/**
  * @brief  通过SPI向FRAM发送一个字节
  * @param  Byte：待发送的字节
  * @retval None
  */
static uint8_t FRAM_SpiSendByte(uint8_t Byte)
{
    uint8_t RxByte;

    HAL_SPI_TransmitReceive(&hspi1, &Byte, &RxByte, 1, 100);

    return RxByte;
}

/**
  * @brief  发送WREN指令以允许写操作
  * @param  None
  * @retval None
  */
static void FRAM_WriteEnable(void)
{
    FRAM_CsLow();
    FRAM_SpiSendByte(0x06);     //发送写允许命令0x06
    FRAM_CsHigh();
}

 /**
  * @brief  向某个存储单元中写入一个字节的数据
  * @param  usAddr：存储单元的地址
  * @param  ucByte：待写入的字节
  * @retval None
  */
void FRAM_WriteByte(uint16_t usAddr, uint8_t ucByte)
{
    FRAM_WriteEnable();

    FRAM_CsLow();

    //发送写数据命令
    FRAM_SpiSendByte(0x02);

    FRAM_SpiSendByte(usAddr >> 8);
    FRAM_SpiSendByte(usAddr & 0xFF);

    //发送待写入的数据
    FRAM_SpiSendByte(ucByte);

    FRAM_CsHigh();

    //发送写禁止命令0x04
    FRAM_CsLow();
    FRAM_SpiSendByte(0x04);
    FRAM_CsHigh();
}


/**
  * @brief  读取某个存储单元中的数据
  * @param  usAddr：存储单元的地址
  * @retval 待读取存储单元中的数据
  */
uint8_t FRAM_ReadByte(uint16_t usAddr)
{
    uint8_t RxByte;

    FRAM_CsLow();       //片选使能

    //发送读数据命令
    FRAM_SpiSendByte(0x03);

    //发送待读取存储单元的地址
    FRAM_SpiSendByte(usAddr >> 8);
    FRAM_SpiSendByte(usAddr & 0xFF);

    RxByte = FRAM_SpiSendByte(0x00);

    FRAM_CsHigh();       //片选禁能

    return RxByte;
}

/**
  * @brief  从FRAM的连续存储区中读取一组数据到指定位置
  * @param  pBuf: 指向读出的数据存储的起始地址
  * @param  Addr: 待读取存储区的起始地址
  * @param  Size: 共读多少个字节
  * @retval None
  */
void FRAM_ReadBuf(uint8_t* pBuf, uint32_t Addr, uint16_t Size)
{
    FRAM_CsLow();       //片选使能

    //发送读数据命令
    FRAM_SpiSendByte(0x03);

    //发送待读取存储单元的地址
    FRAM_SpiSendByte(Addr >> 8);
    FRAM_SpiSendByte(Addr & 0xFF);

    while(Size--)
    {
        *pBuf++ = FRAM_SpiSendByte(0x00);
    }

    FRAM_CsHigh();       //片选禁能
}


/**
  * @brief  从FRAM的连续存储区中读取一组数据到指定位置
  * @param  Addr: 待写入存储区的起始地址
  * @param  pBuf: 指向待写入缓存的指针
  * @param  Size: 待写的字节数
  * @retval None
  */
void FRAM_WriteBuf(uint32_t Addr, const uint8_t *pBuf, uint16_t Size)
{
    FRAM_WriteEnable();

    FRAM_CsLow();

    //发送写数据命令
    FRAM_SpiSendByte(0x02);

    FRAM_SpiSendByte(Addr >> 8);
    FRAM_SpiSendByte(Addr & 0xFF);

    //发送待写入的数据
    while(Size--)
    {
        FRAM_SpiSendByte(*pBuf++);
    }

    FRAM_CsHigh();

    //发送写禁止命令0x04
    FRAM_CsLow();
    FRAM_SpiSendByte(0x04);
    FRAM_CsHigh();
}

/**
  * @brief  FRAM初始化
  * @param  None
  * @retval None
  */
int FRAM_Init(void)
{
    FRAM_WriteStatusRegisterEnable();
    FRAM_CsLow();
    FRAM_SpiSendByte(0x06);
    FRAM_CsHigh();
    FRAM_CsLow();
    FRAM_SpiSendByte(0x01);
    FRAM_SpiSendByte(0x00);
    FRAM_CsHigh();
    FRAM_CsLow();
    FRAM_SpiSendByte(0x04);
    FRAM_CsHigh();

    return RT_EOK;
}

/**
  * @brief  将FRAM从指定位置开始的一块区域写成特定值
  * @param  Addr：起始地址
  * @param  Size：尺寸
  * @param  Val：  指定值
  * @retval None
  */
void FRAM_MemSet(uint32_t Addr, uint8_t Val, uint16_t Size)
{
    FRAM_WriteEnable();

    FRAM_CsLow();

    //发送写数据命令
    FRAM_SpiSendByte(0x02);

    FRAM_SpiSendByte(Addr >> 8);
    FRAM_SpiSendByte(Addr & 0xFF);

    //发送待写入的数据
    while(Size--)
    {
        FRAM_SpiSendByte(Val);
    }

    FRAM_CsHigh();

    //发送写禁止命令0x04
    FRAM_CsLow();
    FRAM_SpiSendByte(0x04);
    FRAM_CsHigh();
}

